import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.swing.JTable;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import resources.Tools;
import resources.VariableAssignmentException;
/**
 * XMLToSpread.java takes in an XML file and parses it into a useable spreadsheet, if it is encrypted with
 * the users RSA key, it will successfully decrypt and send to the FormTable, else it will throw an error
 * to be caught by Frame.java
 *   
 * @author Marc Vandehey, Bryan Gago, Andrew Gifford
 */
public class XMLToSpread 
{
	static XMLInputFactory factory;
	static XMLStreamReader reader;
	static JTable tableToLoad;
	
	static int tempRow;
	static int tempCol;
	static int counter;
	static String tempData = "";
	static String tempAlt = "";
	static String name = "";
	static String value = "";
	static boolean data = false;
	static boolean varName = false;
	static String keyValue = "";
	static String dataIn = "";
	static boolean key = false;
	static boolean keyError;
	static boolean encrypted;
	static SecretKey unlock;
	
	/**
	 * Load takes in a file and loads it into the spreadsheet
	 * 
	 * @param file - The name of the file.
	 * @return Boolean
	 * @throws InvalidKeyException
	 * @throws IllegalBlockSizeException
	 * @throws BadPaddingException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchPaddingException
	 * @throws IOException
	 * @throws InvalidKeySpecException
	 */
	public static boolean load(String file) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException, InvalidKeySpecException
	{
		boolean loaded = true;
		factory = XMLInputFactory.newInstance();
		keyError = true;
		counter = 3;
		factory = XMLInputFactory.newInstance();
		try 
		{
			Reader fileReader = new FileReader(file);
			reader = factory.createXMLStreamReader(fileReader);
			
			while(reader.hasNext())
			{
				process(reader);
				reader.next();
			}
		} // try
		catch (FileNotFoundException e) {
			loaded = false;
		} 
		catch (XMLStreamException e) {
			loaded = false;
		}
		
		return loaded;
	}

	/**
	 * Process is the working process to load the spreadsheet, will parse the XML and decrypt it if
	 * necessary.
	 * 
	 * @param reader - The XMLStreamReader used from the load() method.
	 * @throws XMLStreamException
	 * @throws InvalidKeyException
	 * @throws IllegalBlockSizeException
	 * @throws BadPaddingException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchPaddingException
	 * @throws IOException
	 * @throws InvalidKeySpecException
	 */
	private static void process(XMLStreamReader reader) throws XMLStreamException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException, InvalidKeySpecException
	{
		int eventType = reader.getEventType();

		switch (eventType)
		{
			case XMLStreamConstants.START_ELEMENT:
			{

				data = false;
				varName = false;
				key = false;
				//encrypted = false; // added

				if(reader.getLocalName().equals("data")){
					data = true;
				}
				if(reader.getLocalName().equals("varName")){
					varName = true;
				}
				if(reader.getLocalName().equals("key")){
					key = true;
					//encrypted = true; // added
				}
				
				int count = reader.getAttributeCount();
				for(int i = 0; i<count; i++)
				{
					
					name = reader.getAttributeLocalName(i);
					value = reader.getAttributeValue(i);
					
				
					if(reader.getLocalName() == "row")
					{
						tempRow = Integer.parseInt(value);
					}
					else if(reader.getLocalName() == "col")
					{
						tempCol = Integer.parseInt(value);
					}
				}
				break;
			}
			case XMLStreamConstants.END_ELEMENT:
			{
				break;
			}
			case XMLStreamConstants.CHARACTERS:
			{
				if(data){
					dataIn = reader.getText();
					if(encrypted)
						dataIn = encrypt.decrypt(dataIn);
					Frame.tm2.setValueAt(dataIn, tempRow, tempCol);
				}
				if(key){
					keyValue = reader.getText();
					encrypted = true; // added
					if(keyValue.equals("-1"))
						encrypted = false;
					else
					{
						encrypt.makeSymmetricKey(encrypt.decryptSecretKey(keyValue));
					}
				}
				if(varName){
					String cell = Frame.formTable.getColumnName(tempCol) + tempRow;	
					dataIn = reader.getText().trim();
					if(encrypted)
						dataIn = encrypt.decrypt(dataIn);
					Frame.nameMap.put(dataIn, cell);
					Frame.altNameMap.put(cell, dataIn);
					try {
						Tools.addVariable(dataIn + ": " + cell);
						
					} catch (VariableAssignmentException e1) {
						e1.printStackTrace();
					}
				}

				break;
			}
		} // eventType switch
	}
}
